﻿using MaterialDesignThemes.Wpf;
using Prism.Commands;
using StarryEdge.Core.Enums;
using StarryEdge.Menu.Device.BroadcastDevice;
using StarryEdge.Menu.Device.Model;
using StarryEdge.WPF.Resources.Controls;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace StarryEdge.Menu.Device.ViewModels
{
    public class SerialServerViewModel
    {
        volatile int _lock = 0;
        public string SerialServerName { get; set; } = "IP_Search(1.2)";
        public ObservableCollection<SerialServerModel> DeviceList { get; set; }
        public SerialServerViewModel()
        {
            DeviceList = new ObservableCollection<SerialServerModel>();
        }

        private ISerialServer GetSerialServer()
        {
            return SerialServerName switch
            {
                "IP_Search(1.2)" => new IP_Search_1_2(),
                "HLK_Discover" => new HLK_Discover(),
                _ => null,
            };
        }

        /// <summary>
        /// 搜索设备
        /// </summary>
        public DelegateCommand<Button> SearchDevice => new DelegateCommand<Button>(async sender =>
        {
            DeviceList.Clear();
            _ = DialogHost.Show(new LoadingPopup(), PopUpTypes.Global.ToString()).ConfigureAwait(false);
            var list = await Task.Run(() =>
            {
                IEnumerable<IPAddress> iPHostEntry = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Where(x => x.AddressFamily == AddressFamily.InterNetwork);
                Dictionary<string, UdpClient> udp = new Dictionary<string, UdpClient>();
                foreach (var item in iPHostEntry)
                {
                    if (item.ToString().Contains("169.254"))
                    {
                        continue;
                    }
                    UdpClient client = new UdpClient(new IPEndPoint(item, 22345));
                    client.Client.ReceiveTimeout = 3000;
                    udp.Add(item.ToString(), client);
                }
                ISerialServer serialServer = GetSerialServer();
                List<SerialServerModel> list = new List<SerialServerModel>();
                byte[] buffer = serialServer.GetStream();
                Parallel.ForEach(iPHostEntry, item =>
                {
                    if (item.ToString().Contains("169.254"))
                    {
                        return;
                    }
                    IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 000);
                    string[] strIP = item.ToString().Split('.');
                    for (int i = 0; i < 5; i++)
                    {
                        udp[item.ToString()].Send(buffer, buffer.Length, new IPEndPoint(IPAddress.Parse($"{strIP[0]}.{strIP[1]}.{strIP[2]}.255"), serialServer.Port));
                        System.Threading.Thread.Sleep(20);
                    }
                    Thread.Sleep(300);
                    while (true)
                    {
                        try
                        {
                            byte[] bytes = udp[item.ToString()].Receive(ref endpoint);
                            var model = serialServer.Parsing(bytes, endpoint);
                            while (Interlocked.Exchange(ref _lock, 1) != 0)
                            {
                                _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0; _ = 0;
                            }
                            if (!list.Any(x => x.IPAddress == model.IPAddress)) { list.Add(model); }
                            Interlocked.Exchange(ref _lock, 0);
                        }
                        catch (SocketException)
                        {
                            break;
                        }
                    }
                    udp[item.ToString()].Close();
                    udp[item.ToString()].Dispose();
                });
                return list;
            });
            foreach (var item in list)
            {
                DeviceList.Add(item);
            }
            if (DialogHost.IsDialogOpen(PopUpTypes.Global.ToString())) { DialogHost.Close(PopUpTypes.Global.ToString()); }
        });

        public DelegateCommand<SerialServerModel> MouseDoubleClick => new DelegateCommand<SerialServerModel>(sender =>
        {
            if (sender == null) { return; }
            System.Diagnostics.Process.Start("explorer.exe", $"http://{sender.IPAddress}");
        });
    }
}
